import re

import lldb

from ..common import (
    SummaryRecognizer,
    SynthRecognizer,
    dereference_value,
    error_ctx,
    get_parent_type_by_name,
)
from ..debugger import TypeRegistrator
from ..synth_value import SynthMember, SynthValue


def synth(name: str, expression: str):
    def func(valobj: lldb.SBValue, name: str | None = None):
        value = dereference_value(valobj)
        if name:
            return value.EvaluateExpression(expression, lldb.SBExpressionOptions(), name)
        else:
            return value.EvaluateExpression(expression)

    return SynthMember(name=name, func=func)


class Type(SynthRecognizer, SummaryRecognizer):
    _NS = 'ark::es2panda::checker'
    TYPE_NAME = f'{_NS}::Type'
    OBJECT_TYPE = f'{_NS}::ETSObjectType'
    FUNC_TYPE = f'{_NS}::ETSFunctionType'
    TYPE_PATTERN = re.compile(rf'\b{_NS}::')

    @staticmethod
    def is_type(sbtype: lldb.SBType, internal_dict: dict) -> bool:
        with error_ctx():
            if Type.TYPE_PATTERN.search(sbtype.GetName()):
                return get_parent_type_by_name(sbtype, Type.TYPE_NAME) is not None
            return False

    @staticmethod
    def summary(valobj: lldb.SBValue, internal_dict: dict):
        with error_ctx():
            # t = valobj.GetType()
            value = dereference_value(valobj)
            result = f'{Type._flags(valobj).GetValue()!s} {{ {value.EvaluateExpression('ToStringPrecise()').GetSummary()} }}'
            # is_obj = get_parent_type_by_name(t, Type.OBJECT_TYPE) is not None
            # is_func = get_parent_type_by_name(t, Type.FUNC_TYPE) is not None
            # if is_obj:
            #     result += f'{{ {value.EvaluateExpression("internalName_").GetSummary()} }}'
            # elif is_func:
            #     result += f'{{ {value.EvaluateExpression("name_").GetSummary()} }}'
            return result

    @staticmethod
    def synth(valobj: lldb.SBValue, internal_dict: dict):
        with error_ctx():
            t = valobj.GetType()
            is_obj = get_parent_type_by_name(t, Type.OBJECT_TYPE) is not None
            is_func = get_parent_type_by_name(t, Type.FUNC_TYPE) is not None
            members = [
                synth('__flags', 'typeFlags_'),
            ]
            if is_obj or is_func:
                members.append(synth('__name', 'name_'))
            if is_obj:
                (synth('__internalName', 'internalName_'),)
            return SynthValue(
                valobj=valobj,
                members=members,
            )

    @staticmethod
    def _flags(valobj: lldb.SBValue, name: str | None = None) -> lldb.SBValue:
        value = dereference_value(valobj)
        if name:
            return value.EvaluateExpression('typeFlags_', lldb.SBExpressionOptions(), name)
        else:
            return value.EvaluateExpression('typeFlags_')


class Signature(SummaryRecognizer):
    TYPE_NAME = re.compile(r'\bark::es2panda::checker::Signature\b')

    @staticmethod
    def is_type(sbtype: lldb.SBType, internal_dict: dict):
        with error_ctx():
            return Signature.TYPE_NAME.search(sbtype.GetName()) is not None

    @staticmethod
    def summary(valobj: lldb.SBValue, internal_dict: dict):
        with error_ctx():
            value = dereference_value(valobj)
            return str(value.EvaluateExpression('func_.DumpEtsSrc()').GetSummary())


def register(r: TypeRegistrator):
    r.add_type(
        Signature,
        Type,
    )
    r.add_summary(
        type_name='ark::es2panda::checker::TypeRelation',
        expr='${var.result_}\\{ flags=${var.flags_}, node=${var.node_} \\}',
        novalue=True,
    )
